package com.syl.generator.code;

import com.syl.generator.common.api.BiGenerator;
import com.syl.generator.common.api.bean.DaoBuild;
import com.syl.generator.common.api.bean.JavaBeanBuild;
import com.syl.generator.common.api.bean.MapperBuild;
import com.syl.generator.common.bean.DatabaseBean;
import com.syl.generator.common.bean.SystemConfigBean;
import com.syl.generator.common.bean.TableColumnBean;
import com.syl.generator.common.dao.SqlLiteMapper;
import com.syl.generator.common.enums.DbType;
import com.syl.generator.common.util.CommonUtil;
import com.syl.generator.common.util.ConfigReadUtil;
import com.syl.generator.common.util.DbConnectionUtil;
import com.syl.generator.common.util.StringUtils;
import com.syl.generator.view.bean.GeneratorConfig;
import org.apache.log4j.Logger;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * 负责mybatis部分代码生成
 *
 * @author syl
 * @create 2018-04-03 10:59
 **/
public class MybatisCodeGenerator {
    private static final Logger LOG = Logger.getLogger(MybatisCodeGenerator.class);
    private static final List<String> DTO_MATCHING_TYPE = new ArrayList<>();//日期类型匹配项
    private static final boolean SERIALIZABLE = ConfigReadUtil.getYmlBoolean("generate.serializable");
    static {
        DTO_MATCHING_TYPE.add("date");
        DTO_MATCHING_TYPE.add("datetime");
        DTO_MATCHING_TYPE.add("time");
        DTO_MATCHING_TYPE.add("timestamp");
    }
    private SystemConfigBean systemConfig;
    private String beanName;
    private String functionTarget;
    private String functionName;
    private String projectFolder;
    private String xmlDirectory;
    private String basePath;
    private String mapperPath;

    public MybatisCodeGenerator(GeneratorConfig config, DatabaseBean databaseBean) {
        databaseBean.setTableName(config.getTableName());
        String FS = File.separator;
        SqlLiteMapper dao = DbConnectionUtil.getSqliteDao();
        this.systemConfig  = dao.selectSystemConfig();
        this.beanName = config.getDomainObjectName();
        this.functionTarget = config.getFunctionTarget();
        this.functionName = functionTarget.substring(functionTarget.lastIndexOf(".")+1);
        this.projectFolder = config.getProjectFolder();
        this.xmlDirectory = config.getXmlDirectory();
        this.basePath = projectFolder + config.getJavaDirectory() + FS;
        String temp  = basePath + functionTarget.replace(".", FS)+FS+"dao"+FS;
        this.mapperPath = StringUtils.isEmpty(xmlDirectory) ? temp : projectFolder + xmlDirectory + FS + functionName + FS;

        startGenerator(config,databaseBean);//开始生成
    }

    public void startGenerator(GeneratorConfig config, DatabaseBean databaseBean){
        boolean actualColumnName = config.isUseActualColumnName();
        List<TableColumnBean> columnList = DbConnectionUtil.getTableColumnList(databaseBean,1);
        JavaBeanBuild javaBeanBuild = new JavaBeanBuild(basePath, beanName,functionTarget,systemConfig)
            .setLombok(config.isLombok()).setRemark(config.getTableComment()+" POJO")
            .addAllFiled(columnList,config.isUseActualColumnName());
        LOG.info("bean reference "+javaBeanBuild.getReference());
        if(SERIALIZABLE)javaBeanBuild.addJimplements("Serializable").addImport("java.io.Serializable");
        //生成普通pojo
        new BiGenerator(javaBeanBuild, true);
        JavaBeanBuild dtoBuild = null;
        if(!config.isSimpleJavaBean()){
            dtoBuild = new JavaBeanBuild(basePath, beanName + "DTO", functionTarget,systemConfig)
                    .setLombok(config.isLombok()).setRemark(config.getTableComment()+" DTO")
                    .addAllFiled(initDtoColumn(columnList),actualColumnName);
            if(SERIALIZABLE)dtoBuild.addJimplements("Serializable").addImport("java.io.Serializable");
            //生成DTO pojo
            LOG.info("bean reference "+dtoBuild.getReference());
            new BiGenerator(dtoBuild, true);
        }

        //生成DAO 接口
        DaoBuild daoBuild = new DaoBuild(basePath, config,systemConfig)
            .setRemark(config.getTableComment()+"类 Dao").setJavaBeanReference(javaBeanBuild.getReference())
            .setDtoReference(dtoBuild == null ? null : dtoBuild.getReference()).addAllFiled(columnList,actualColumnName);
        new BiGenerator(daoBuild, false);

        //生成mapper
        MapperBuild mapperBuild = new MapperBuild(mapperPath, config, DbType.valueOf(databaseBean.getDbType()),false)
            .setNamespace(daoBuild.getReference()).setBeanReference(javaBeanBuild.getReference())
            .addAllFiled(columnList,initDtoColumn(columnList),actualColumnName).setSystemConfig(systemConfig);

        MapperBuild mapperBuild2 = new MapperBuild(mapperPath, config, DbType.valueOf(databaseBean.getDbType()),true)
                .setNamespace(daoBuild.getReference()).setBeanReference(javaBeanBuild.getReference())
                .addAllFiled(columnList,initDtoColumn(columnList),actualColumnName).setSystemConfig(systemConfig);
        new BiGenerator(mapperBuild,true);//生成的mapper
        new BiGenerator(mapperBuild2,false);//供新增sql添加的mapper
        LOG.info("======MybatisCodeGenerator生成完成=======");
    }

    /**
     * 初始化dto 列
     * @param list
     * @return
     */
    private List<TableColumnBean> initDtoColumn(List<TableColumnBean> list){
        List<TableColumnBean> tempList = CommonUtil.deepCopy(list);
        for(TableColumnBean bean:list){
            String type = bean.getColumnType();
            if(DTO_MATCHING_TYPE.contains(type.toLowerCase())){
                String name = bean.getColumnName();
                String comment = bean.getColumnComment();
                TableColumnBean temp1 = new TableColumnBean();
                temp1.setColumnType(type).setColumnName(name+"Start").setOriginaColumnName(name)
                        .setColumnComment("按"+name+"的开始时间查找").setAcquired(true);
                TableColumnBean temp2 = new TableColumnBean();
                temp2.setColumnType(type).setColumnName(name+"End").setOriginaColumnName(name)
                        .setColumnComment("按"+name+"的截止时间查找").setAcquired(true);
                tempList.add(temp1);
                tempList.add(temp2);
            }
        }
        return tempList;
    }

}
